using System;
using System.Collections;
using System.Windows.Forms;
using System.ComponentModel;
using System.Reflection;
using System.Diagnostics;

namespace CSettingsUI
{
	/// <summary>
	/// PropertyConverter reflects the public readable and writeable properties for a given object.
	/// Every setting item is based on<c></c>
	/// <list type="table">
	/// <listheader>
	/// <term>term</term>
	/// <description>description</description>
	/// </listheader>
	/// <item>
	/// <term>CategoryAttribute</term>
	/// <description>Categories</description>
	/// </item>
	/// <item>
	/// <term>DescriptionAttribute</term>
	/// <description>Label</description>
	/// </item>
	/// <item>
	/// <term>Property</term>
	/// <description>The public read and writeable property to convert.</description>
	/// </item>			
	/// <item>
	/// <term>string PropertyNameValidating(PropertyType newValue)</term>
	/// <description>Occurs when the control is validating. Return String.Empty for OK, validating messge to Cancel.</description>
	/// </item>
	/// </list>	
	/// </summary>
	public class PropertyConverter
	{
		#region attributes	
		/// <summary>Event is fired if a value form the current reflected object has changed.</summary>
		public EventHandler ValueChanged;
		#endregion

		#region public interface
		/// <summary>
		/// Binds the public r/w properties from a class Array to the Gui implementing <code>IPropertyConverterGui</code>.
		/// </summary>
		/// <param name="sourceClass"></param>
		/// <param name="targetGui"></param>
		public PropertyConverter(object[] sourceClass, IPropertyConverterGui targetGui)
		{
            Debug.WriteLine("PropertyConverter");

			foreach(object obj in sourceClass)
			{
				this.Layout(targetGui,obj);
			}
			
		}
		/// <summary>
		/// Binds the public r/w properties from <code>sourceClass</code> to the Gui implementing <code>IPropertyConverterGui</code>.
		/// </summary>
		/// <param name="sourceClass"></param>
		/// <param name="targetGui"></param>
		public PropertyConverter(object sourceClass, IPropertyConverterGui targetGui)
		{
            Debug.WriteLine("PropertyConverter");

			this.Layout(targetGui,sourceClass);			
		}		
		#endregion

		#region events
		/// <summary>
		/// Reflect public properties from <code>sourceObject</code>. Foreach reflected r/w propertie a control is created and binded.		
		/// </summary>
		/// <param name="optionConveterGui"></param>
		/// <param name="sourceObject"></param>
		private void Layout(IPropertyConverterGui optionConveterGui,object sourceObject)
		{
            Debug.WriteLine("Layout");

			Hashtable categories = new Hashtable();			
			System.Resources.ResourceManager rs = new System.Resources.ResourceManager(sourceObject.GetType());
			//if(rs.GetResourceSet();

            string translatedName;
			//
			Type type = sourceObject.GetType();
			System.Reflection.PropertyInfo[] properties = type.GetProperties();
			foreach(System.Reflection.PropertyInfo pi in properties)
			{	
				System.ComponentModel.CategoryAttribute optionItem = null;
				System.Attribute[] atbs =  (System.Attribute[]) pi.GetCustomAttributes(typeof(System.ComponentModel.CategoryAttribute),true);
				if(atbs.GetLength(0) ==0) continue;				
				optionItem = (System.ComponentModel.CategoryAttribute) atbs[0];
				//
				translatedName = null;
				//
				try
				{					
					translatedName = rs.GetString(optionItem.Category);					
				} 
				catch{}
				translatedName = (translatedName!=null) ? translatedName : optionItem.Category;
				//
				if (!categories.ContainsKey(translatedName))
				{
					categories.Add(translatedName, new ArrayList());
				}
				//
				((ArrayList)categories[translatedName]).Add(pi);
			}			
			//
			Control groupControl;
			foreach(DictionaryEntry entry in categories)
			{
				groupControl = null;				
				groupControl = optionConveterGui.CreateGroup(entry.Key.ToString());
				if(groupControl ==null) continue;
				//
				new FlowManager(groupControl);
				//
				foreach(System.Reflection.PropertyInfo propertyInfo in ((ArrayList)entry.Value))
				{
					IPropertyConverterControl ctl = optionConveterGui.CreateControl(propertyInfo);
					if(ctl == null) continue;
					//
					translatedName = null;
					try
					{
						translatedName = rs.GetString(propertyInfo.Name);						
					} 
					catch(Exception exc)
                    {
                        System.Diagnostics.Debug.WriteLine(exc.Message);

                    }
					try
					{
                        //if (ctl.GetType() != typeof(ButtonOption))
                        
                            System.Reflection.PropertyInfo nameProp = ctl.GetType().GetProperty("Name");
                            if (nameProp == null)
                            {
                                nameProp = ctl.GetType().GetProperty("Text");
                            }
                            //
                            if ((nameProp != null) && (nameProp.CanWrite))
                            {
                                nameProp.SetValue(ctl, (translatedName != null) ? translatedName : propertyInfo.Name, null);
                            }
                        
                        //else
                        //{
                        //    Debug.WriteLine("ButtonOption");
                        //}
					}
                    catch (Exception exc)
                    {
                        System.Diagnostics.Debug.WriteLine(exc.Message);

                    }
					//
                    CustomDataBinding db = new CustomDataBinding(sourceObject, propertyInfo, ctl, optionConveterGui);					
					db.ValueChanged +=	new EventHandler(OnValueChanged);
					//
                    try
                    {
                        groupControl.Controls.Add((Control)ctl);
                    }
                    catch (Exception exc)
                    {
                        System.Diagnostics.Debug.WriteLine(exc.Message);

                    }

				}
			}
			//
			rs.ReleaseAllResources();
		}
		/// <summary>
		/// Value changed event is fired if a property is dirty.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void OnValueChanged(object sender, EventArgs e)
		{
            Debug.WriteLine("OnValueChanged");
			if(ValueChanged!=null)
			{
				ValueChanged(this, EventArgs.Empty);
			}
		}
		#endregion

	
	}
	/// <summary>
	/// <see cref="PropertyConverter"/> can handle controls implementing <c>IPropertyConverterControl</c>.
	/// </summary>
	public interface IPropertyConverterControl
	{
		/// <summary>Gets or sets the <code>value</code> for the control.</summary>
		object Value{get;set;}
	}
	/// <summary>
	/// <see cref="PropertyConverter"/> can handle <c>IPropertyConverterGui</c> to communicate with UI.
	/// </summary>
	public interface IPropertyConverterGui
	{
		/// <summary>
		/// Request for a new Option Group.
		/// </summary>
		/// <param name="group">Display Text used to visualize Group</param>
		Control CreateGroup(string group);
		/// <summary>
		/// Request to create a item (Control) for <code>propertyInfo</code>
		/// </summary>
		/// <param name="group">Display Text used to visualize Group</param>
		/// <param name="propertyInfo">Reflected propertie</param>
		/// <returns></returns>
		IPropertyConverterControl CreateControl(System.Reflection.PropertyInfo propertyInfo);
		/// <summary>
		/// Validation messages output
		/// </summary>
		/// <param name="control">Control which cause the validation message.</param>
		/// <param name="message">Message that is thrown in validation code.</param>
		void SetError(IPropertyConverterControl control, string message);	
	}
}
